﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Speech.Recognition;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils
{
    /// <summary>
    /// 此类用于解析基本 Markdown 语法，但标记由用户自已定义。例如：
    /// 
    /// 这是一段【包含（加粗）和[（倾斜）且有下划线]的】文本。
    /// 
    /// </summary>
    public class 格式解析器
    {
        /// <summary>
        /// 解析器。应使用字典来初始化，然后调用“解析”方法。
        /// 此类虽然支持多行文本，但主要是用来支持对基本 Markdown 文本段落中的格式符（如加粗、倾斜、下划线、行内代码块）进行解析。
        /// </summary>
        /// <param name="marks">用 Dictionary 是为了防止同名称的格式标记存在。</param>
        public 格式解析器(Dictionary<string, 格式标记> marks)
        {
            this._标记集 = marks;
        }

        private Dictionary<string, 格式标记> _标记集 = null;

        public Dictionary<string, 格式标记> 标记集 { get { return _标记集; } }

        /// <summary>
        /// 解析成一系列的文本片段组成的列表。
        /// 注意：此方法不适合用来解析过长的文本，也不适合用于解析整个文档。
        /// 可以使用 纯文本处理器 类的 取文本片段() 方法先获取某个文本片段，再用此方法解析。
        /// </summary>
        /// <param name="srcText">用于解析的源文本。</param>
        /// <param name="marks"></param>
        /// <returns>返回一个列表。</returns>
        public List<TextPiece> 解析(string srcText)
        {
            if (string.IsNullOrEmpty(srcText)) return null;
            if (_标记集 == null || _标记集.Count <= 0) return null;

            var sb = new StringBuilder();
            foreach (var mark in _标记集)
            {
                sb.Append("(" + mark.Value.标记文本 + ")|");
            }

            var pieces = Utils.Text.SplitToPiecesByRegex(sb.ToString().TrimEnd(new char[] { '|', }), srcText, true, true);

            foreach (var piece in pieces)
            {
                if (piece.IsMartchText)  // 格式文本
                {
                    // 这里判断并决定（开启|关闭）某种效果。
                    foreach (var mark in _标记集)
                    {
                        if (mark.Value.正则器 != null && mark.Value.正则器.Match(piece.SourceText).Success)
                        {
                            switch (mark.Value.标记位置)
                            {
                                case 标记位置.首标记:
                                    {
                                        mark.Value.开启状态 = true;
                                        break;
                                    }
                                case 标记位置.尾标记:
                                    {
                                        mark.Value.开启状态 = false;
                                        if(mark.Value.关联标记 != null)
                                        {
                                            mark.Value.关联标记.开启状态 = false;
                                        }
                                        break;
                                    }
                                default:
                                    {
                                        mark.Value.开启状态 = !mark.Value.开启状态;
                                        break;
                                    }
                            }
                        }
                    }
                }
                else  // 正常文本
                {
                    foreach (var mark in _标记集)
                    {
                        if (mark.Value.开启状态)
                        {
                            if (piece.AppendInfos == null)
                            {
                                piece.AppendInfos = new List<string>();
                            }

                            piece.AppendInfos.Add(mark.Value.标记名称);
                        }
                    }
                }
            }

            return pieces;
        }
    
        public static List<TextPiece> 基本格式解析(string srcText)
        {
            if (string.IsNullOrEmpty(srcText)) return null;

            var pieces = Text.SplitToPiecesByRegex(@"\(:.*:\)", srcText);
            var txt = new StringBuilder();
            foreach(var piece in pieces)
            {
                if (piece.IsMartchText)
                {
                    piece.ReplacedText = piece.SourceText.Replace("_", "<-&#95;->");
                    txt.Append(piece.ReplacedText);
                }
                else txt.Append(piece.SourceText);
            }

            srcText = txt.ToString();
            srcText = Regex.Replace(srcText, @"\*{4,}|_{4,}", "");
            srcText = Regex.Replace(srcText, @"\*\*|(?<=[^\\])_(?<=[^\\])_", "<-/b/->");
            srcText = Regex.Replace(srcText, @"\*|(?<=(^|[^\(\\]))_", "<-/i/->");

            var dict = new Dictionary<string, 格式标记>
            {
                // 快捷图标
                { "快捷图标开", new 格式标记(@"\(:", "快捷图标", 标记位置.首标记) },
                { "快捷图标关", new 格式标记(@":\)", "快捷图标", 标记位置.尾标记) },
                // 快捷图标的路径可能含有 _ 字符，必须先处理！！

                { "图像链接开", new 格式标记(@"!\[.*\]\(", "图像链接", 标记位置.首标记) },
                { "图像链接关", new 格式标记(@"\)", "图像链接", 标记位置.尾标记) },
                // Markdown 格式的图像链接也大概率有 _ 字符，同样必须先处理！！

                { "加粗", new 格式标记(@"<-/b/->", "加粗", 标记位置.自动标记) },
                { "倾斜", new 格式标记(@"<-/i/->", "倾斜", 标记位置.自动标记) },
                { "代码块", new 格式标记(@"`", "代码块", 标记位置.自动标记) },
                { "下划线开", new 格式标记(@"<u>", "下划线", 标记位置.首标记) },
                { "下划线关", new 格式标记(@"<\/u>", "下划线", 标记位置.尾标记) },
                // 注意：传入字典的 Key 不能重复，但开关标记的名称是可以重复的！
                // 例如这里下划线开、关标记的名称均为“下划线”！
                { "删除线开", new 格式标记(@"\[=", "删除线", 标记位置.首标记) },
                { "删除线关", new 格式标记(@"=\]", "删除线", 标记位置.尾标记) },

                // Html 内置标签
                { "Html加粗开", new 格式标记(@"<b>", "Html加粗", 标记位置.首标记) },
                { "Html加粗关", new 格式标记(@"</b>", "Html加粗", 标记位置.尾标记) },

                { "Html强调开", new 格式标记(@"<em>", "Html强调", 标记位置.首标记) },
                { "Html强调关", new 格式标记(@"</em>", "Html强调", 标记位置.尾标记) },

                { "Html强强调开", new 格式标记(@"<strong>", "Html强强调", 标记位置.首标记) },
                { "Html强强调关", new 格式标记(@"</strong>", "Html强强调", 标记位置.尾标记) },

            };

            dict["快捷图标关"].关联标记 = dict["快捷图标开"];
            dict["下划线关"].关联标记 = dict["下划线开"];
            dict["删除线关"].关联标记 = dict["删除线开"];

            dict["Html加粗关"].关联标记 = dict["Html加粗开"];
            dict["Html强调关"].关联标记 = dict["Html强调开"];
            dict["Html强强调关"].关联标记 = dict["Html强强调开"];
            dict["图像链接关"].关联标记 = dict["图像链接开"];

            var parse = new 格式解析器(dict);
            return parse.解析(srcText);
        }
    }

    public class 格式标记
    {
        public 格式标记(string ruleText, string name, 标记位置 location)
        {
            this.标记文本 = ruleText;
            this.标记名称 = name;
            this.标记位置 = location;

            if (string.IsNullOrEmpty(标记文本) == false)
            {
                this.正则器 = new Regex(标记文本, RegexOptions.IgnoreCase | RegexOptions.Multiline);
            }
        }

        public 格式标记 关联标记 { get; set; }

        public string 标记文本 { get; set; }

        public string 标记名称 { get; set; }

        public Regex 正则器 { get; }

        public 标记位置 标记位置 { get; set; }

        /// <summary>
        /// 对于首标记，永远是 True，对于尾标记，永远是 False。
        /// 对于不方便确定的标记，则碰到下一个时反转 True | False。
        /// </summary>
        public bool 开启状态 { get; set; }
    }

    public enum 标记位置
    {
        首标记,     // 适用于能看出头尾标记的情况，例如：“”
        尾标记,
        自动标记,   // 适用于无法分清的情况，例如：`，既表示开头，又表示结束。
    }
}
